home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / strategy / xpat2-1.000 / xpat2-1 / xpat2-1.04 / src / hints.c < prev    next >
C/C++ Source or Header  |  1994-05-09  |  8KB  |  306 lines

  1. /*****************************************************************************/
  2. /*                                         */
  3. /*                                         */
  4. /*    X patience version 2 -- module hints.c                     */
  5. /*                                         */
  6. /*    Functions for the ``display hint'' part                     */
  7. /*    written by Heiko Eissfeldt and Michael Bischoff                 */
  8. /*    see COPYRIGHT.xpat2 for Copyright details                 */
  9. /*                                         */
  10. /*                                         */
  11. /*****************************************************************************/
  12. #include "xpatgame.h"
  13.  
  14. #define RESET_HINTS        (-2)
  15. #define ALL_HINTS          (-1)
  16.  
  17.  
  18.  
  19. static Move lasthint;
  20.  
  21. void cmd_DoHint(void) {
  22.     if (lasthint == NO_MOVE) {
  23.     show_message(TXT_NOHINTGIVEN);
  24.     } else {
  25.     store_move(do_move(SRCIND(lasthint), DSTPILE(lasthint)));
  26.     }
  27. }
  28.  
  29. #define MAXHINTS 256
  30. static struct hintstruct {
  31.     int srcind, dstpile;
  32.     int value;
  33. } hinttab[MAXHINTS];
  34. static int hints, showhint;    /* hints is number of hints in table (-1: unknown), showhint is index */
  35.  
  36. static int hintcmp(const void *a, const void *b)
  37. {   return ((const struct hintstruct *)b)->value - ((const struct hintstruct *)a)->value;
  38. }
  39.  
  40. /* ind == -1 => no marked cards, show all possible moves
  41.     otherwise show move for block ind  */
  42.  
  43. static void collect_hints(Cardindex ind)
  44. {
  45.     int begsrcpile, endsrcpile;
  46.     int pile;
  47.  
  48.     if (ind != ALL_HINTS) {
  49.     begsrcpile = endsrcpile = getpile(ind);
  50.     } else {
  51.     begsrcpile = 0;
  52.     endsrcpile = game.numpiles-1;
  53.     }
  54.     
  55.     /* gather all possibilities, if necessary */
  56.     hints = 0;
  57.     for (pile = begsrcpile; pile <= endsrcpile; pile++) {
  58.     int dstpile, uppercard, stacksrc, havestack;
  59.  
  60.     /* check all moves which go from this pile */
  61.     /* if pile is empty, no moves are possible */
  62.     if (EMPTY(pile))
  63.         continue;
  64.     if (pile == IDECK && !(rules.variant & DECK_VISIBLE))
  65.         continue;
  66.     /* if there is a block selected already, use it */
  67.     /* otherwise, take the maximum number of movable cards */
  68.     uppercard = (ind == ALL_HINTS) ? maxsequence(pile, INDEX_OF_FIRST_CARD(pile)) : ind;
  69.     if (game.piletype[pile] == Stack)
  70.         stacksrc = -1;    /* avoid stack to stack moves */
  71.         else {
  72.         stacksrc = stackable(pile);
  73.         if (ind != ALL_HINTS && stacksrc != uppercard)
  74.         stacksrc = -1;    /* block differs => no moves to stack */
  75.     }
  76.     havestack = 0;
  77.     for (dstpile = 0; dstpile < game.numpiles; ++dstpile) {
  78.         /* in a first step, reject some moves */
  79.         int srcindex;
  80.         if (rules.variant & HINTS_LESSER)
  81.         if (pile <= dstpile)
  82.             break;
  83.         if (pile == dstpile)
  84.         continue;
  85.         switch (game.piletype[dstpile]) {
  86.         case Slot:
  87.         if (EMPTY(dstpile)) {
  88.             if ((rules.move_bits & ES_MASK) != ES_KINGS)
  89.             continue;  /* don't fill empty slots, if allowed for all */
  90.             /* now: ugly code! */
  91.             /* kings may be moved, if they don't come from a stack */
  92.             /* and they don't leave an empty slot */
  93.             if (game.piletype[pile] == Stack && ind == ALL_HINTS)
  94.             continue;
  95.             if (game.piletype[pile] == Slot && game.ind[pile] == uppercard)
  96.             continue;
  97.             /* king's move allowed! */
  98.         }
  99.         if (IS_JOKER(game.cards[INDEX_OF_LAST_CARD(dstpile)]))
  100.             continue;        /* don't move to jokers */
  101.         /* fall through */
  102.         srcindex = uppercard;
  103.         break;
  104.         case Tmp:
  105.         case FaceupDeck:
  106.         case FacedownDeck:
  107.         continue;
  108.         case Stack:    /* for stacks, choose another srcindex */
  109.         if (stacksrc == -1 || havestack)
  110.             continue;
  111.         srcindex = stacksrc;
  112.         break;
  113.         default:
  114.         srcindex = 0;    /* to keep compiler happy */
  115.         exit(EXIT_FAILURE);    /* cannot happen! */
  116.         }
  117.         if (move_valid(srcindex, dstpile)) {
  118.         /* hint found. store source and destination, if acceptable  */
  119.         hinttab[hints].value = rules.good_hint ?
  120.             (*rules.good_hint)(srcindex, dstpile) : 100;    /* 100 is default value */
  121.         if (hinttab[hints].value) {
  122.             if (hinttab[hints].value < 2 && ind == ALL_HINTS) {
  123.             /* don't suggest bad moves */
  124.             continue;
  125.             }
  126.             /* accept the hint */
  127.             if (game.piletype[dstpile] == Stack && !(rules.variant & STACKS_MULTI))
  128.             havestack = 1;
  129.             hinttab[hints].srcind = srcindex;
  130.             hinttab[hints].dstpile = dstpile;
  131.             if (++hints == MAXHINTS)
  132.             break;
  133.         }
  134.         }
  135.     }
  136.     }
  137.     /* sort hints by relevance */
  138.     qsort(hinttab, (size_t)hints, sizeof(hinttab[0]), hintcmp);
  139.     showhint = hints;    /* will show either first or last hint */
  140. }
  141.  
  142. /* this function returns a value (the higher the better) of the move done (or 0, if no move) */
  143.  
  144. int generic_automove(Cardindex srcindex)    /* pile is "movable" */
  145. {   Pileindex i, srcpile;
  146.  
  147.     cmd_ResetHints();
  148.     collect_hints(srcindex);
  149.     if (hints) {
  150.     store_move(do_move(hinttab[0].srcind, hinttab[0].dstpile));
  151.     return hinttab[0].value;
  152.     }
  153.     /* no move to non-empty piles possible, try to move to empty slot */
  154.     srcpile = getpile(srcindex);
  155.     for (i = game.numpiles - 1; i >= 0; --i) {
  156.     if (i == srcpile)
  157.         continue;
  158.     if (game.piletype[i] == Tmp && game.piletype[srcpile] == Tmp)
  159.         continue;
  160.     if (move_valid(srcindex, i)) {
  161.         store_move(do_move(srcindex, i));
  162.         return 1;
  163.     }
  164.     }
  165.     cmd_ResetHints();    /* MUST reset the hints! */
  166.     return 0;    /* no move => extremely ugly */
  167. }
  168.  
  169.  
  170. static void mysprintf(char *p, const char *fmt, ...) {
  171.     va_list args;
  172.     va_start(args, fmt);
  173.  
  174.     while (*fmt) {
  175.     if (*fmt != '%')
  176.         *p++ = *fmt++;
  177.     else {
  178.         int arg;
  179.         arg = va_arg(args, int);
  180.         switch (*++fmt) {
  181.         case 'R':
  182.         strcpy(p, TXT_RANK[RANK(arg)]);
  183.         p += strlen(p);
  184.         break;
  185.         case 'S':
  186.         strcpy(p, TXT_SUIT[SUIT(arg)]);
  187.         p += strlen(p);
  188.         break;
  189.         case 'P':
  190.         switch(game.piletype[arg]) {
  191.         case FaceupDeck:
  192.             strcpy(p, TXT_DECK);
  193.             break;
  194.         case FacedownDeck:
  195.             strcpy(p, TXT_IDECK);
  196.             break;
  197.         case Slot:
  198.             strcpy(p, TXT_SLOT);
  199.             p += strlen(p);
  200.             sprintf(p, " %d", arg - rules.numstacks + 1);
  201.             break;
  202.         case Stack:
  203.             strcpy(p, TXT_STACK);
  204.             p += strlen(p);
  205.             sprintf(p, " %d", arg + 1);
  206.             break;
  207.         case Tmp:
  208.             strcpy(p, TXT_TMP);
  209.             p += strlen(p);
  210.             sprintf(p, " %d", arg-rules.numstacks-rules.numslots + 1);
  211.             break;
  212.         }
  213.         p += strlen(p);
  214.         break;
  215.         default:
  216.         *p++ = *fmt;
  217.         }
  218.         ++fmt;
  219.     }
  220.     }
  221.     va_end(args);
  222.     *p = '\0';
  223. }
  224.  
  225. static void display_hint(struct hintstruct *p) {
  226.     int dstpile, srcpile, srcval;
  227.     char buf[180];
  228.  
  229.     dstpile = p->dstpile;
  230.     srcpile = getpile(p->srcind);
  231.     srcval = game.cards[p->srcind];
  232.  
  233.     mysprintf(buf, TXT_CANMOVE, srcpile, srcval, srcval, dstpile);
  234.     show_message(buf);
  235.     show_arrow(True);
  236. }
  237.  
  238.  
  239. static int forward = 1;
  240.  
  241. static int hint(Cardindex ind, boolean dodisplay) {
  242.     show_arrow(False);    /* if any arrow visible, clear it */
  243.  
  244.     if (ind == RESET_HINTS) {
  245.     hints = showhint = -1;
  246.     game.arrow_srcind = -1;
  247.     game.arrow_dstpile = -1;
  248.     lasthint = NO_MOVE;
  249.     return 0;
  250.     }
  251.     /* printf("hints = %d\n", hints); */
  252.     if (hints < 0)
  253.     collect_hints(ind);
  254.  
  255.     if (!hints) {
  256.         if (dodisplay)
  257.         show_message(TXT_NOHINTS);
  258.     return 0;
  259.     } else {
  260.     showhint = (forward ? (showhint + 1) : (showhint + hints)) % (hints+1);
  261.     if (showhint == hints)
  262.         show_message(TXT_WRAPPING);
  263.     else {
  264.         struct hintstruct *p;
  265.         p = hinttab + showhint;
  266.         game.arrow_srcind = p->srcind;
  267.         game.arrow_dstpile = p->dstpile;
  268.         lasthint = MOVE(p->srcind, p->dstpile);
  269.         if (dodisplay)
  270.         display_hint(p);
  271.     }
  272.     return 1;
  273.     }
  274. }
  275.  
  276. void cmd_ResetHints(void) {
  277.     hint(RESET_HINTS, 0);
  278. }
  279.  
  280. void cmd_AllMoves(void) {
  281.     forward = 1;
  282.     hint(RESET_HINTS, 0);
  283.     while (hint(ALL_HINTS, 0)) {
  284.     /* XFlush(dpy); */
  285.     cmd_DoHint();
  286.     /* XFlush(dpy); */
  287.     }
  288. }
  289.  
  290.  
  291. void cmd_NextHint(void)    {    /* show next hint in queue */
  292.     forward = 1;
  293.     if (game.srcind < 0)
  294.     hint(ALL_HINTS, 1);
  295.     else
  296.     hint(game.srcind, 1);
  297. }
  298.  
  299. void cmd_PreviousHint(void) {    /* show previous hint */
  300.     forward = 0;
  301.     if (game.srcind < 0)
  302.     hint(ALL_HINTS, 1);
  303.     else
  304.     hint(game.srcind, 1);
  305. }
  306.